﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace OpenExpressApp
{
    public class Unity : IUnity, IDisposable
    {
        public static readonly IUnity Instance = new Unity();

        private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
        private IDictionary<Type, Type> _typeMapping = new Dictionary<Type, Type>();
        private IDictionary<Type, object> _instanceMapping = new Dictionary<Type, object>();

        private Unity() { }
        ~Unity()
        {
            this.Dispose(false);
        }

        #region IUnity Members

        public TAbstract Resolve<TAbstract>() where TAbstract : class
        {
            return this.Resolve(typeof(TAbstract)) as TAbstract;
        }

        public object Resolve(Type abstractType)
        {
            this._lock.EnterReadLock();

            object result = null;
            if (this._instanceMapping.TryGetValue(abstractType, out result) == false)
            {
                Type concreateType = null;
                if (this._typeMapping.TryGetValue(abstractType, out concreateType))
                {
                    result = Activator.CreateInstance(concreateType);
                }
                //else
                //{
                //    throw new InvalidOperationException("还没有注册该类型。");
                //}
            }

            this._lock.ExitReadLock();

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TAbstract"></typeparam>
        /// <typeparam name="TConcreate">
        /// 目前只支持拥有无参数的构造函数的类型
        /// </typeparam>
        public void RegisterType<TAbstract, TConcreate>()
            where TAbstract : class
            where TConcreate : class
        {
            RegisterType(typeof(TAbstract), typeof(TConcreate));
        }

        public void RegisterType(Type astractType, Type concreteType)
        {
            this._lock.EnterWriteLock();

            this._typeMapping[astractType] = concreteType;

            this._lock.ExitWriteLock();
        }

        public void RegisterInstance(Type astractType, object singleton)
        {
            this._lock.EnterWriteLock();

            this._instanceMapping[astractType] = singleton;

            this._lock.ExitWriteLock();
        }

        public void RegisterInstance<TAbstract>(object singleton) where TAbstract : class
        {
            RegisterInstance(typeof(TAbstract), singleton);
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                this._lock.Dispose();
            }
        }

        #endregion
    }
}
